package org.sensornet2010.co2sh.core;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;

import android.util.Log;

public class RemoteServer {
	
	private static String CGI_STATUS		=	"/server_state.php";
	private static String CGI_SENDDATA		=	"/send_data.php";
	static String CGI_AMR2WAV				=	"/uploaded.php"; // "/amr2wav.php";
	
	private String url;
	SoundDecoder decoder;
	
	public RemoteServer(String url) {
		this.url = url;
		this.decoder = new SoundDecoder(this);
	}

	/**
	 * Gets the state of the server
	 * @return string
	 */
	public String getState(){
		SensornetUtil.debug("RemoteServer:getState()" + this.url);
		try {
			return getURLContent(this.url + CGI_STATUS);
		} catch (Exception e) {
			throw new SensornetException(e, SensornetException.COMMUNICATION_ERROR, e.toString());
		}
	}
	
	
	/**
	 * Sends data on sendValueData
	 * @param data		SoundData
	 * @return			String
	 */
	public String sendData(SensorData data){
		SensornetUtil.debug("RemoteServer:sendData()");
		try {
			this.sendValueData(data);
			//Thread.sleep(1 * 1000);
		} catch (Exception e) {
			SensornetUtil.debug("ERROR:sendData():" + data.getTimestamp().getTime());
			throw new SensornetException( e, SensornetException.COMMUNICATION_ERROR, e.toString());
		}
		return "OK";	
	}
	
	private String sendAudioData(SensorData data) throws Exception{
		SensornetUtil.debug("RemoteServer:sendAudioData()");
		String resp = null;
		Hashtable<String, String> params = new Hashtable<String, String>();
		params.put("SENSOR_ID", data.getId());
		params.put("TIMESTAMP", "" + data.getTimestamp().getTime());
		params.put("DURATION", "" + data.getDuration());
		params.put("PROTOCOL", "" + data.getSensuinoVersion());
		String fileName = data.getId() + "_" + data.getTimestamp().getTime() + ".amr";
		byte[] response = fileUploadPost(this.url + CGI_SENDDATA, params, fileName,  "binary/octet-stream", data.getSound());
		resp = new String(response);
		return resp;	
	}
	
	
	/**
	 * Sends data value
	 * @param data		SensorData
	 * @return			String
	 */
	private String sendValueData(SensorData data) {
		int co2Value = this.decoder.decodeSound(data.getSound());
		data.setCo2Value(co2Value);
		if (SensornetConfiguration.PACHUBE_ACTIVE)
			this.sendValue2Pachube(co2Value);
		SensornetUtil.debug("sendValueData:CO2=" + co2Value);
		return "OK";
	}
	
	private String sendValue2Pachube(int co2Value){
		// http://community.pachube.com/quickstart
		try {
			String url = SensornetConfiguration.PACHUBE_FEED + "?key=" + SensornetConfiguration.PACHUBE_API_KEY;
			URL u = new URL(url);
			HttpURLConnection hc = (HttpURLConnection)u.openConnection(); 
			hc.setRequestMethod("PUT");
			hc.setDoOutput(true);
		    hc.setDoInput(true);
		    //hc.setAllowUserInteraction(false);
		    String content = SensornetConfiguration.PACHUBE_FEED_DATASTREAM + "," + co2Value; 
		    byte[] postBytes = content.getBytes();
			OutputStream dout = hc.getOutputStream();
			dout.write(postBytes);
			dout.close();
			int ch;
			InputStream is = hc.getInputStream();
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			while ((ch = is.read()) != -1) {
				bos.write(ch);
			}
			//String response = new String(bos.toByteArray());
		} catch (Exception e) {
			SensornetUtil.debugException(e);
		}
		
		return "OK";
	}
	
	
	/**
	 * Converts amr byte[] into wav byte[]
	 * @param amrContent		byte[]
	 * @return wavContent		byte[]
	 */
	public byte[] convertAmr2Wav(byte[] amrContent){
		byte[] wavContent = null;
		Date date = new Date();
		try {
			//String url = this.url + CGI_AMR2WAV;
			String url = this.url + CGI_AMR2WAV;
			Hashtable params = new Hashtable();
			String fileName = SensornetConfiguration.SENSOR_ID + "_" + date.getTime() + ".amr";
			String contentType = "application/octet-stream";
			wavContent = fileUploadPost(url, params, fileName, contentType, amrContent);
			//Thread.sleep(1 * 1000);
		} catch (Exception e) {
			e.printStackTrace();
			//throw new RuntimeException(e);
		}
		return wavContent;
	}

	/*
	 * Returns a String with content of the specified URL.
	 */
	public static String getURLContent(String url) throws IOException {
		// code snippet from http://www.java2s.com/Code/Java/Network-Protocol/UseBufferedReadertoreadcontentfromaURL.htm
		URL u = new URL(url);
		HttpURLConnection urlConnection = (HttpURLConnection)u.openConnection();
	    BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
	    String urlString = "";
	    String current;
	    while ((current = in.readLine()) != null) {
	      urlString += current;
	    }
	    in.close();
	    return urlString;
	}
	
	/*
	 * 
	 */
	public static byte[] fileUploadPost(String url, Hashtable params, String fileName, String contentType, byte[] fileBytes) throws Exception{
		HttpMultipartRequest req;
		req = new HttpMultipartRequest(url, params, "file", fileName, contentType, fileBytes);
		byte[] resp= req.send();
		return resp;
	}
	
	
	private static class HttpMultipartRequest {
		/*
		 * Example code from: http://wiki.forum.nokia.com/index.php/HTTP_Post_multipart_file_upload_in_Java_ME
		 * adapted to the use of java.net. classes instead of J2ME classes
		 * 
		 * 
			// -----Java client code
			// Here's a code snippet to upload a file via HttpMultipartRequest class:
			byte[] fileBytes = getFileBytes(); // retrieve file bytes with your own
												// code
			Hashtable params = new Hashtable();
			params.put("custom_param", "param_value");
			params.put("custom_param2", "param_value2");
			HttpMultipartRequest req = new HttpMultipartRequest(
					"http://www.server.com/uploadScript.php", params,
					"upload_field", "original_filename.png", "image/png", fileBytes);
			byte[] response = req.send();
			
			//----PHP server code
			<?php
				$filesize = filesize($_FILES['upload_field']['tmp_name']);
				echo "The uploaded file size is " . $filesize . " bytes\n";
	 			foreach($_POST as $key => $value)
				{
					echo "Parameter name: " . $key . ", value: " . $value . "\n";
				}
			?>
		 */
		
		
		static final String BOUNDARY = "----------V2ymHFg03ehbqgZCaKO6jy";

		byte[] postBytes = null;
		String url = null;

		public HttpMultipartRequest(String url, Hashtable params,
				String fileField, String fileName, String fileType,
				byte[] fileBytes) throws Exception {
			this.url = url;
			String boundary = getBoundaryString();
			String boundaryMessage = getBoundaryMessage(boundary, params,
					fileField, fileName, fileType);
			String endBoundary = "\r\n--" + boundary + "--\r\n";
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			bos.write(boundaryMessage.getBytes());
			bos.write(fileBytes);
			bos.write(endBoundary.getBytes());
			this.postBytes = bos.toByteArray();
			bos.close();
		}

		String getBoundaryString() {
			return BOUNDARY;
		}

		String getBoundaryMessage(String boundary, Hashtable params,
				String fileField, String fileName, String fileType) {
			StringBuffer res = new StringBuffer("--").append(boundary).append(
					"\r\n");
			Enumeration keys = params.keys();
			while (keys.hasMoreElements()) {
				String key = (String) keys.nextElement();
				String value = (String) params.get(key);

				res.append("Content-Disposition: form-data; name=\"").append(
						key).append("\"\r\n").append("\r\n").append(value)
						.append("\r\n").append("--").append(boundary).append(
								"\r\n");
			}
			res.append("Content-Disposition: form-data; name=\"").append(
					fileField).append("\"; filename=\"").append(fileName)
					.append("\"\r\n").append("Content-Type: ").append(fileType)
					.append("\r\n\r\n");
			return res.toString();
		}

		public byte[] send() throws Exception {
			//HttpConnection hc = null;
			HttpURLConnection hc = null;
			InputStream is = null;
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			byte[] res = null;
			Exception ex = null;
			try {
				//hc = (HttpConnection) Connector.open(url);
				URL u = new URL(url);
				hc = (HttpURLConnection)u.openConnection(); 
				hc.setRequestProperty("Content-Type","multipart/form-data; boundary=" + getBoundaryString());
				//hc.setRequestMethod(HttpConnection.POST);
				hc.setRequestMethod("POST");
				//OutputStream dout = hc.openOutputStream();
				// code from http://www.jguru.com/faq/view.jsp?EID=62798
				hc.setDoOutput(true);
			    hc.setDoInput(true);
			    //hc.setAllowUserInteraction(false);

				OutputStream dout = hc.getOutputStream();
				dout.write(postBytes);
				dout.close();
				int ch;
				//is = hc.openInputStream();
				is = hc.getInputStream();
				while ((ch = is.read()) != -1) {
					bos.write(ch);
				}
				res = bos.toByteArray();
			} catch (Exception e) {
				e.printStackTrace();
				ex = e;
			} finally {
				try {
					if (bos != null)
						bos.close();

					if (is != null)
						is.close();

					if (hc != null)
						//hc.close();
						hc.disconnect();
				} catch (Exception e2) {
					e2.printStackTrace();
					ex = e2;
				}
			}
			if (ex != null)
				throw new RuntimeException("ERROR.send():" + ex.getClass() + "=" + ex.getMessage());
			return res;
		}
	}	
	
}